/**
 * Copyright (C) 2011 Moss Computing <support@mosscomputing.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.oslef.csv;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.regex.Pattern;

import org.oslef.csv.CSVWriter.QuoteSpec.QuoteMode;

public final class CSVWriter {
	public static class QuoteSpec {
		public enum QuoteMode{EVERYTHING, AS_NEEDED}
		
		private final String quote;
		private final String quoteReplacement;
		private final boolean quoteEverything;
		
		public QuoteSpec(String quote, String quoteReplacement, QuoteMode mode) {
			super();
			this.quote = quote;
			this.quoteReplacement = quoteReplacement;
			switch(mode){
			case AS_NEEDED:
				quoteEverything = false;
				break;
			case EVERYTHING:
				quoteEverything = true;
				break;
			default: throw new RuntimeException("Unsupported mode: " + mode);
			}
		}
	}
	
	private final Writer writer;
	private final QuoteSpec quoting;
	private final String quotePattern;
	
	private final char delimiter = ',';
	private boolean isNewline = true;
	
	public CSVWriter(File file) throws IOException {
		this(new FileWriter(file), new QuoteSpec("\"", "'", QuoteMode.EVERYTHING));
	}
	
	public CSVWriter(Writer writer) {
		this(writer, new QuoteSpec("\"", "'", QuoteMode.EVERYTHING));
	}

	public CSVWriter(Writer writer, final QuoteSpec quoting) {
		super();
		this.writer = writer;
		this.quoting = quoting;
		quotePattern = Pattern.quote(quoting.quote);
	}

	public void flush() throws IOException {
		writer.flush();
	}
	
	public void close() throws IOException {
		writer.close();
	}
	
	public void newLine() throws IOException {
		isNewline = true;
		writer.append('\n');
	}
	public void write(String value) throws IOException {
		if(!isNewline){
			writer.append(delimiter);
		}
		isNewline = false;
		boolean valueHasQuotes = value.indexOf(quoting.quote)!=-1;
		
		boolean hasDelimiter = value.indexOf(delimiter)!=-1;
		boolean hasNewLine = value.indexOf('\n')!=-1;
		
		if(quoting.quote!=null){
			if(quoting.quoteEverything || (valueHasQuotes || hasDelimiter || hasNewLine)){
				// WE'RE QUOTING
				writer.append(quoting.quote);
				if(valueHasQuotes){
					writer.append(value.replaceAll(quotePattern, quoting.quoteReplacement));
				}else{
					writer.append(value);
				}
				writer.append(quoting.quote);
			}else{
				writer.append(value);
			}
		}else{
			
			if(valueHasQuotes || hasDelimiter || hasNewLine){
				throw new IOException("The following value must be quoted, but this is not configured to print quotes: \"" + value + "\"");
			}else{
				writer.append(value);
			}
		}
	}
}
